/*
** pud_map.h for pud in mrcellophane/libpud/sys/NetBSD
** 
** Made by solomon hykes
** Login   <torgau@gmail.com>
** 
** Started on  Tue May 17 13:46:21 2005 solomon hykes
** Last update Tue May 17 21:02:59 2005 solomon hykes
*/

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>

#include "pud_sys.h"

char	*get_mapfilename(int pid)
{
  char	*str;

  str = malloc(32); /* Enough for "/proc/<pid>/maps" */
 sprintf(str, "/proc/%d/maps", pid);
  return (str);
}

char	*getmapdata(int fd, int *len)
{
  char	*buf = NULL;
  int	bufLen = 0;
  int	ret;

  *len = 0;
  bufLen = 0;
  while (1)
    {
      if (bufLen < (*len) + 1024)
	{
	  buf = realloc(buf, bufLen + 1024);
	  bufLen += 1024;
	}
      ret = read(fd, buf + *len, 1024);
      if (ret <= 0)
	return (buf);
      (*len) += ret;
    }
}

pud_map	*pud_get_maps(pud_process *p)
{
  char	*mapfilename;
  int	fd;
  char	*mapdata;
  char	*buf;
  int	len;
  char	*mapdataEnd;
  char	*line;
  char	*word;
  pud_map	*maps = NULL;
  pud_map	*lastMap = NULL;

  mapfilename = get_mapfilename(p->pid);
  fd = open(mapfilename, O_RDONLY);
  buf = mapdata = getmapdata(fd, &len);
  mapdataEnd = mapdata + len;
  while (((line = strsep(&mapdata, "\n")) != NULL) && (mapdata < mapdataEnd))
    {
      pud_map	*m;
      char	*word;

      if (*line == '\0')
	continue;
      m = malloc(sizeof(*m));

      if (((word = strsep(&line, "-")) == NULL) || (*word == 0))
	{ free(m); free(buf); continue; }
      m->start = strtoul(word, (char **)NULL, 16);
      
      if (((word = strsep(&line, "\t ")) == NULL) || (*word == 0))
	{ free(m); free(buf); continue; }
      m->size = strtoul(word, (char **)NULL, 16) - m->start;

      if (((word = strsep(&line, "\t ")) == NULL) || (*word == 0))
	{ free(m); free(buf); continue; }
      m->prot = 0;
      if (word[0] == 'r')
	m->prot |= PROT_READ;
      if (word[1] == 'w')
	m->prot |= PROT_WRITE;
      if (word[2] == 'x')
	m->prot |= PROT_EXEC;
      m->next = NULL;
      if (lastMap == NULL)
	maps = lastMap = m;
      else
	{
	  lastMap->next = m;
	  lastMap = m;
	}
    }
  free(buf);
  return (maps);
}
